package com.sec.android.app.myfiles.module.search;

import android.app.LoaderManager;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.MatrixCursor;
import android.mtp.MtpConstants;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.CursorTreeAdapter;
import android.widget.ImageView;
import android.widget.ExpandableListView;
import android.widget.TextView;

import com.samsung.android.sdk.slinkcloud.CloudGatewayMediaStore;
import com.sec.android.app.myfiles.R;
import com.sec.android.app.myfiles.feature.CloudMgr;
import com.sec.android.app.myfiles.feature.DlpMgr;
import com.sec.android.app.myfiles.feature.HoverMgr;
import com.sec.android.app.myfiles.feature.PrivateModeMgr;
import com.sec.android.app.myfiles.feature.detailinfo.DetailsInfoMgr;
import com.sec.android.app.myfiles.fragment.search.SearchTextView;
import com.sec.android.app.myfiles.info.AppConstants;
import com.sec.android.app.myfiles.info.FileType;
import com.sec.android.app.myfiles.info.MediaFile;
import com.sec.android.app.myfiles.log.Log;
import com.sec.android.app.myfiles.module.abstraction.FileRecord;
import com.sec.android.app.myfiles.module.abstraction.FileRecord.CloudType;
import com.sec.android.app.myfiles.module.cloud.CloudFileRecord;
import com.sec.android.app.myfiles.module.local.file.LocalFileRecord;
import com.sec.android.app.myfiles.module.local.home.HomeFileRecord;
import com.sec.android.app.myfiles.navigation.NavigationInfo;
import com.sec.android.app.myfiles.provider.DbTableInfo;
import com.sec.android.app.myfiles.provider.DbTableInfo.COLUMN_ID;
import com.sec.android.app.myfiles.thumbnail.ThumbnailImageView;
import com.sec.android.app.myfiles.thumbnail.ThumbnailMgr;
import com.sec.android.app.myfiles.util.FileUtils;
import com.sec.android.app.myfiles.util.PreferenceUtils;
import com.sec.android.app.myfiles.util.SemFwWrapper;
import com.sec.android.app.myfiles.util.StorageMonitor;
import com.sec.android.app.myfiles.util.UiUtils;
import com.sec.android.app.myfiles.widget.listview.ReverseCheckBox;

import java.io.File;
import java.util.ArrayList;
import java.util.Locale;

public class SearchAdapter extends CursorTreeAdapter implements LoaderManager.LoaderCallbacks<Cursor> {
    private static final String STORAGE_ID = "_id";
    private static final String STORAGE_NAME = "alias_name";
    private static final String FILE_PATH = "_data";
    protected static final String[] GROUP_PROJECTION = {STORAGE_ID, STORAGE_NAME};
    private static final String IS_DIR_QUERY = "case when mime_type = 'vnd.asp.dir/dir' then 1 else 0 end as isDirectory";
    private static final String IS_DIR = "isDirectory";
    private static final String SEARCH_NAME = "substr(_data,1+length(rtrim(_data,replace(_data,'/','')))) as searchName";
    private static final String PARENT_PATH = "rtrim(_data, _display_name) as parentPath";
    private static final String FILE_ID = "source_media_id";
    private static final String PARENT_ID = "parent_cloud_id";
    private static final int GROUP_INDICATOR_UPDATE_TIME = 150;
    private final String[] mParentProjection = {FILE_ID, PARENT_ID};
    private static final String SAMSUNG_DRIVE_NAME = "Samsung Drive";

    public interface SEARCH_STORAGE_ID {
        int RECENT = 0;
        int INTERNAL = 1;
        int GOOGLE_DRIVE = 2;
        int SAMSUNG_DRIVE = 3;
        int CATEGORY = 4;
        int DOWNLOAD_HISTORY = 5;
        int SDCARD = 100;
        int PRIVATE = 200;
    }

    private static class SearchViewHolder {
        public SearchTextView Name;
        public TextView Path;
        public TextView Size;
        public ThumbnailImageView thumbnail;
        public ImageView fileTypeIcon;
        public ReverseCheckBox checkbox;
        public ImageView privateIcon;
        public ImageView dlpIcon;
    }

    private boolean mIsChecked = false;
    private boolean mSelectAll = false;
    protected final boolean mShowHidden;
    protected final Context mContext;
    private final LoaderManager mLoaderManager;
    private final Cursor mGroupCursor;
    protected DbTableInfo mSearchDbTableInfo;
    private final SearchFileRecord mCurRecord;
    protected final FileRecord mPreRecord;
    private final SearchFragment mFragment;
    private final SparseIntArray mGroupPosition = new SparseIntArray();
    private final SparseIntArray mGroupChildCount = new SparseIntArray();
    private final SparseBooleanArray mGroupLoading = new SparseBooleanArray();

    public SearchAdapter(Context context, NavigationInfo navigationInfo, LoaderManager loaderManager) {
        super(null, context, false);

        mContext = context;
        mLoaderManager = loaderManager;
        mShowHidden = PreferenceUtils.getShowHiddenFiles(mContext);
        mFragment = (SearchFragment) navigationInfo.getCurFragment();
        mSearchDbTableInfo = SearchDbTableInfo.getInstance();
        mCurRecord = (SearchFileRecord) navigationInfo.getCurRecord();
        mPreRecord = mCurRecord.getPreRecord();
        mGroupCursor = createGroupCursor();
        setGroupCursor(mGroupCursor);
    }

    protected Cursor createGroupCursor() {
        MatrixCursor groupCursor = new MatrixCursor(GROUP_PROJECTION);
        ArrayList<String[]> groups = new ArrayList<>();
        String preRecordPath = mPreRecord.getFullPath();
        CloudMgr cloudMgr = CloudMgr.getInstance(mContext);

        if (mContext != null && !TextUtils.isEmpty(preRecordPath)) {
            //addGroupList(GroupList, Search storage ID, Search storage name, isMounted, isFirst header)
            addGroupList(groups, SEARCH_STORAGE_ID.INTERNAL, mContext.getString(UiUtils.getInternalStorageRootResId()), true, true);
            addGroupList(groups, SEARCH_STORAGE_ID.SDCARD, mContext.getString(R.string.sd_card),
                    StorageMonitor.isSdCardMounted(), StorageMonitor.isSdCardPath(preRecordPath)); //isMounted, isFirst
            addGroupList(groups, SEARCH_STORAGE_ID.PRIVATE, mContext.getString(R.string.private_storage),
                    StorageMonitor.isPrivateModeDirMounted(mContext), FileUtils.isPrivateFolder(preRecordPath)); //isMounted, isFirst

            if (UiUtils.isCloudGatewayEnabled(mContext)) {
                addGroupList(groups, SEARCH_STORAGE_ID.SAMSUNG_DRIVE, SAMSUNG_DRIVE_NAME,
                        cloudMgr.isAccountRetrieved(CloudType.SamsungDrive) && cloudMgr.isSignedIn(CloudType.SamsungDrive), //isMounted
                        StorageMonitor.isSamsungDrivePath(preRecordPath)); //isFirst
                addGroupList(groups, SEARCH_STORAGE_ID.GOOGLE_DRIVE, mContext.getString(R.string.google_drive),
                        cloudMgr.isAccountRetrieved(CloudType.GoogleDrive) && cloudMgr.isSignedIn(CloudType.GoogleDrive), //isMounted
                        StorageMonitor.isGoogleDrivePath(preRecordPath)); //isFirst
            }
        }

        for (String[] group : groups) {
            groupCursor.addRow(group);
        }

        return groupCursor;
    }

    private void addGroupList(ArrayList<String[]> groups, int searchId, String searchName, boolean isMounted, boolean isFirst) {
        if (isMounted) {
            groups.add(isFirst ? 0 : groups.size(), new String[]{String.valueOf(searchId), searchName});
        }
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle bundle) {
        mGroupLoading.put(mGroupPosition.get(id), true);

        return new CursorLoader(mContext, getUri(id), getProjection(id), getSelection(id), getSelectionArgs(), getOrderBy(id));
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        int groupPosition = mGroupPosition.get(loader.getId());

        try {
            setChildrenCursor(groupPosition, cursor);
        } catch (NullPointerException e) {
            Log.e(this, "NullPointerException:" + e.toString());
        }

        mGroupLoading.put(groupPosition, false);
        mGroupChildCount.put(groupPosition, getChildrenCount(groupPosition));
        mFragment.onLoadFinished();
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        try {
            setChildrenCursor(mGroupPosition.get(loader.getId()), null);
        } catch (NullPointerException e) {
            Log.e(this, "NullPointerException:" + e.toString());
        }
    }

    @Override
    public void setChildrenCursor(int groupPosition, Cursor childrenCursor) {
        if (childrenCursor == null || childrenCursor.isClosed()) {
            return;
        }

        try {
            super.setChildrenCursor(groupPosition, childrenCursor);
        } catch (NullPointerException e) {
            Log.e(this, "NullPointerException:" + e.toString());
        }
    }

    @Override
    protected Cursor getChildrenCursor(Cursor groupCursor) {
        if (groupCursor == null) {
            return null;
        }

        int groupId = groupCursor.getInt(groupCursor.getColumnIndex(STORAGE_ID));
        mGroupPosition.put(groupId, groupCursor.getPosition());

        Loader<Cursor> loader = mLoaderManager.getLoader(groupId);
        if (loader != null && !loader.isReset()) {
            mLoaderManager.restartLoader(groupId, null, this);
        } else {
            mLoaderManager.initLoader(groupId, null, this);
        }

        return null;
    }

    @Override
    protected View newGroupView(Context context, Cursor groupCursor, boolean isExpanded, ViewGroup parent) {
        View view = null;
        LayoutInflater layoutInflater = LayoutInflater.from(context);
        if (layoutInflater != null) {
            view = layoutInflater.inflate(R.layout.search_result_subheader, parent, false);
        }

        return view;
    }

    @Override
    protected void bindGroupView(View view, Context context, Cursor groupCursor, final boolean isExpanded) {
        TextView groupHeaderTextView = (TextView) view.findViewById(R.id.group_header_text);
        final ImageView groupHeaderIndicator = (ImageView) view.findViewById(R.id.group_header_indicator);
        if (mFragment.getExpandingGroupPosition() == groupCursor.getPosition()) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    groupHeaderIndicator.animate().rotation(isExpanded ? 0 : 180).setDuration(200L);
                    mFragment.setExpandingGroupPosition(-1);
                }
            }, GROUP_INDICATOR_UPDATE_TIME);
        } else {
            groupHeaderIndicator.setRotation(isExpanded ? 0 : 180);
        }

        String groupTitle = getGroupTitle(groupCursor.getString(groupCursor.getColumnIndex(STORAGE_NAME)));

        int childrenCount = mGroupChildCount.get(groupCursor.getPosition());
        boolean isEmpty = childrenCount == 0;
        boolean isSingle = mGroupCursor.getCount() == 1;

        if (isEmpty) {
            groupHeaderTextView.setVisibility(View.GONE);
            groupHeaderIndicator.setVisibility(View.GONE);
        } else {
            groupHeaderTextView.setText(groupTitle + " (" + String.format(Locale.getDefault(), "%d", childrenCount) + ")");
            groupHeaderTextView.setVisibility(View.VISIBLE);
            groupHeaderIndicator.setVisibility(isSingle ? View.GONE : View.VISIBLE);
        }

        if (UiUtils.isTalkBackEnabled(mContext)) {
            groupHeaderTextView.setContentDescription(groupTitle + " " + mContext.getString(R.string.tts_header));
        }
    }

    @Override
    protected View newChildView(Context context, Cursor cursor, boolean isLastChild, ViewGroup parent) {
        View view = null;
        LayoutInflater layoutInflater = LayoutInflater.from(context);
        if (layoutInflater != null) {
            view = layoutInflater.inflate(R.layout.search_list_item, parent, false);
        }

        SearchViewHolder vh = new SearchViewHolder();
        if (view != null) {
            vh.checkbox = (ReverseCheckBox) ((ViewStub) view.findViewById(R.id.check_stub)).inflate();
            vh.Name = (SearchTextView) view.findViewById(R.id.file_name);
            vh.Path = (TextView) view.findViewById(R.id.file_path);
            vh.Size = (TextView) view.findViewById(R.id.file_size);
            vh.thumbnail = (ThumbnailImageView) view.findViewById(R.id.thumbnail);
            vh.fileTypeIcon = (ImageView) view.findViewById(R.id.file_type_icon);
            vh.privateIcon = (ImageView) view.findViewById(R.id.private_icon);
            vh.dlpIcon = (ImageView) view.findViewById(R.id.dlp_icon);
            view.setTag(vh);
        }
        return view;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        mIsChecked = mFragment.isItemChecked(groupPosition, childPosition);
        return super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent);
    }

    @Override
    protected void bindChildView(View view, Context context, Cursor childCursor, boolean isLastChild) {
        SearchViewHolder vh = (SearchViewHolder) view.getTag();
        boolean isLocalRecord = childCursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.DEVICE_ID) == -1;
        FileRecord record;

        if (isLocalRecord) {
            record = getLocalFileRecord(childCursor);
            _bindLocalView(view, context, record, vh);
        } else {
            record = getCloudFileRecord(childCursor);
            _bindCloudView(view, context, record, vh);
        }

        if (vh.checkbox != null) {
            updateChildVisibility(vh, view, isEnabled(childCursor));
        }

        bindContentDescription(context, view, record);
    }

    public FileRecord getFileRecord(Cursor groupCursor, Cursor childCursor) {
        FileRecord ret = null;

        if (groupCursor != null && childCursor != null) {
            int searchStorageId = groupCursor.getInt(groupCursor.getColumnIndex(STORAGE_ID));
            if (searchStorageId == SEARCH_STORAGE_ID.GOOGLE_DRIVE || searchStorageId == SEARCH_STORAGE_ID.SAMSUNG_DRIVE) {
                ret = getRealCloudFileRecord(groupCursor, childCursor);
            } else {
                ret = getLocalFileRecord(childCursor);
            }
        }

        return ret;
    }

    public FileRecord getLocalFileRecord(Cursor cursor) {
        FileRecord ret = null;
        if (cursor != null) {
            int pathIndex = mSearchDbTableInfo.getIndex(COLUMN_ID.PATH);
            String full_path = cursor.getString(pathIndex);
            int id = cursor.getInt(mSearchDbTableInfo.getIndex(COLUMN_ID.ID));
            File file = SemFwWrapper.file(full_path);
            String parent = file.getParent();
            String name = file.getName();
            long size = cursor.getLong(mSearchDbTableInfo.getIndex(COLUMN_ID.SIZE));
            long date = cursor.getLong(mSearchDbTableInfo.getIndex(COLUMN_ID.DATE)) * 1000;
            int isDirectory = cursor.getInt(mSearchDbTableInfo.getIndex(COLUMN_ID.IS_DIRECTORY));
            int fileType = isDirectory == 0 ? MediaFile.getFileTypeForMimeType(
                    cursor.getString(mSearchDbTableInfo.getIndex(COLUMN_ID.MIME_TYPE)))
                    : FileType.FOLDER;
            if (fileType == 0) {
                fileType = MediaFile.getFileType(full_path, mContext);
            }
            ret = new LocalFileRecord(id, parent, name, size, date, fileType, 0, -1, -1);
        }
        return ret;
    }

    private FileRecord getCloudFileRecord(Cursor cursor) {
        CloudFileRecord ret = null;

        if (cursor != null) {
            final int id = cursor.getInt(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns._ID));
            final int deviceId = cursor.getInt(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.DEVICE_ID));
            final String fileId = cursor.getString(cursor.getColumnIndex(FILE_ID));
            final String path = cursor.getString(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.DATA));
            final String name = cursor.getString(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.DISPLAY_NAME));
            final long date = cursor.getLong(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.DATE_MODIFIED));
            final long size = cursor.getLong(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.SIZE));
            final int isDirectory = cursor.getInt(cursor.getColumnIndex(IS_DIR));
            int fileType = (isDirectory == 0) ? MediaFile.getFileTypeForMimeType(
                    cursor.getString(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.MIME_TYPE)))
                    : FileType.FOLDER;

            if (fileType == 0) {
                fileType = MediaFile.getFileType(name, mContext);
            }

            ret = new CloudFileRecord(id, deviceId, fileId, path, name, size, date * 1000, fileType, isDirectory);
        }
        return ret;
    }

    private void _bindLocalView(View view, Context context, FileRecord record, SearchViewHolder vh) {
        if (record != null) {
            if (vh.Name != null) {
                vh.Name.setText(record.getName(), mCurRecord.getSearchedName());
            }

            if (vh.Path != null) {
                vh.Path.setText(StorageMonitor.convertPathToDisplayedPath(mContext, record.getFullPath()));
            }

            if (vh.Size != null) {
                if (record.isDirectory()) {
                    DetailsInfoMgr.getInstance().loadChildCount(context, record, vh.Size);
                } else {
                    vh.Size.setText(UiUtils.makeFileSizeString(mContext, record.getSize()));
                }
            }

            if (vh.privateIcon != null) {
                if (FileUtils.isPrivateFolder(record.getPath())) {
                    vh.privateIcon.setVisibility(View.VISIBLE);
                } else {
                    vh.privateIcon.setVisibility(View.GONE);
                }
            }

            if (!record.isDirectory() && vh.dlpIcon != null) {
                boolean isDLP = DlpMgr.getInstance(mContext).isDlpFile(record);

                if (isDLP) {
                    vh.dlpIcon.setVisibility(View.VISIBLE);
                } else {
                    vh.dlpIcon.setVisibility(View.GONE);
                }
            }

            if (record.exists(mContext) || mPreRecord.getStorageType() == FileRecord.StorageType.Downloads) {
                if (vh.thumbnail != null && vh.fileTypeIcon != null) {
                    vh.thumbnail.setThumbnailView(mFragment, record, view);
                    ImageView imageView = ThumbnailMgr.getInstance(context).loadThumbnail(record, vh.thumbnail, vh.fileTypeIcon);
                    if (!mFragment.isSelectActionMode()) {
                        HoverMgr.getInstance(context).setHoverListener(vh.thumbnail, record, mFragment, mContext);
                    }

                    if (imageView == null) {
                        vh.fileTypeIcon.setImageDrawable(MediaFile.getFileTypeDrawable(context, record));
                    }
                }
            }
        }
    }

    private void _bindCloudView(View view, Context context, FileRecord record, SearchViewHolder vh) {
        if (record != null) {
            if (vh.Name != null) {
                vh.Name.setText(record.getName(), mCurRecord.getSearchedName());
            }

            if (vh.Path != null) {
                vh.Path.setText("/" + getCloudTitle(record) + record.getPath());
            }

            if (vh.Size != null) {
                if (record.isDirectory()) {
                    vh.Size.setText("");
                } else {
                    vh.Size.setText(UiUtils.makeFileSizeString(mContext, record.getSize()));
                }
            }

            if (vh.privateIcon != null) {
                vh.privateIcon.setVisibility(View.GONE);
            }

            if (!record.isDirectory() && vh.dlpIcon != null) {
                vh.dlpIcon.setVisibility(View.GONE);
            }

            if (vh.thumbnail != null && vh.fileTypeIcon != null) {
                vh.thumbnail.setThumbnailView(mFragment, record, view);
                ImageView imageView = ThumbnailMgr.getInstance(context).loadThumbnail(record, vh.thumbnail, vh.fileTypeIcon);

                if (imageView == null) {
                    vh.fileTypeIcon.setImageDrawable(MediaFile.getFileTypeDrawable(context, record));
                }
            }
        }
    }

    private String getCloudTitle(FileRecord record) {
        String title = "";
        int deviceId = 0;

        if (record instanceof CloudFileRecord) {
            deviceId = ((CloudFileRecord) record).getDeviceId();
        }

        if (mGroupCursor != null && !mGroupCursor.isClosed() && mGroupCursor.moveToFirst()) {
            do {
                if (deviceId == mGroupCursor.getInt(mGroupCursor.getColumnIndex(STORAGE_ID))) {
                    title = getGroupTitle(mGroupCursor.getString(mGroupCursor.getColumnIndex(STORAGE_NAME)));
                }
            } while (mGroupCursor.moveToNext());
        }

        return title;
    }

    private void updateChildVisibility(SearchViewHolder vh, View view, boolean isEnabled) {
        view.setClickable(!isEnabled);
        view.setAlpha(isEnabled ? 1.0f : 0.4f);
        view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
        vh.checkbox.setReverse(mSelectAll);
        vh.checkbox.setChecked(mIsChecked);
        View parent = (View) view.getParent();
        if (mSelectAll && parent != null) {
            parent.setActivated(!vh.checkbox.isChecked());
        }
        view.setActivated(isEnabled && vh.checkbox.isChecked());    //for select state
        vh.checkbox.setVisibility(mFragment.isSelectActionMode() && isEnabled ? View.VISIBLE : View.GONE);
    }

    private void bindContentDescription(Context context, View view, FileRecord record) {
        if (view != null && isDetailList(view)) {
            if (record.getFileType() == FileType.FOLDER) {
                boolean showHidden = PreferenceUtils.getShowHiddenFiles(context);
                view.setContentDescription(UiUtils.getContentDescription(context, record.getName(), record.getFileType(), false, false)
                        + " "
                        + context.getResources().getQuantityString(R.plurals.n_items, record.getItemCount(showHidden),
                        record.getItemCount(showHidden)) + " " + UiUtils.makeTimeString(mContext, record.getDate()));
            } else {
                view.setContentDescription(UiUtils.getContentDescription(context, record.getName(), record.getFileType(), false, false)
                        + " "
                        + sizeSetter(record.getSize()) + " " + UiUtils.makeTimeString(mContext, record.getDate()));
            }
        }
    }

    private boolean isEnabled(Cursor childCursor) {
        boolean isEnabled = true;

        if (childCursor != null && mFragment != null && mFragment.isSelectActionMode()) {
            if (mFragment.isNothingSelected()) {
                return true;
            }
            String filePath = childCursor.getString(childCursor.getColumnIndex(FILE_PATH));
            boolean isLocalRecord = childCursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.DEVICE_ID) == -1;
            long packedPosition = mFragment.getPackedPosition();
            int selectedGroupPosition = ExpandableListView.getPackedPositionGroup(packedPosition);
            Cursor selectedGroupCursor = getGroup(selectedGroupPosition);
            if (selectedGroupCursor != null) {
                int selectedStorageId = selectedGroupCursor.getInt(selectedGroupCursor.getColumnIndex(STORAGE_ID));

                switch (selectedStorageId) {
                    case SEARCH_STORAGE_ID.INTERNAL:
                        isEnabled = StorageMonitor.isInternalPath(filePath);
                        break;
                    case SEARCH_STORAGE_ID.SDCARD:
                        isEnabled = StorageMonitor.isSdCardPath(filePath);
                        break;
                    case SEARCH_STORAGE_ID.PRIVATE:
                        isEnabled = FileUtils.isPrivateFolder(filePath);
                        break;
                    case SEARCH_STORAGE_ID.GOOGLE_DRIVE:
                    case SEARCH_STORAGE_ID.SAMSUNG_DRIVE:
                        isEnabled = !isLocalRecord && (childCursor.getInt(childCursor.getColumnIndex(
                                CloudGatewayMediaStore.Files.FileColumns.DEVICE_ID)) == selectedStorageId);
                        break;
                    default:
                        break;
                }
            }
        }

        return isEnabled;
    }

    protected Uri getUri(int id) {
        Uri ret;

        switch (id) {
            case SEARCH_STORAGE_ID.GOOGLE_DRIVE:
            case SEARCH_STORAGE_ID.SAMSUNG_DRIVE:
                ret = CloudGatewayMediaStore.CloudFiles.getCloudFileUri(id);
                break;
            default:
                ret = FileUtils.MEDIA_PROVIDER_URI;
                break;
        }

        return ret;
    }

    private String[] getProjection(int id) {
        String[] ret;
        switch (id) {
            case SEARCH_STORAGE_ID.GOOGLE_DRIVE:
            case SEARCH_STORAGE_ID.SAMSUNG_DRIVE:
                ret = new String[]{
                        CloudGatewayMediaStore.Files.FileColumns._ID, CloudGatewayMediaStore.Files.FileColumns.DATA,
                        CloudGatewayMediaStore.Files.FileColumns.DISPLAY_NAME, CloudGatewayMediaStore.Files.FileColumns.SIZE,
                        CloudGatewayMediaStore.Files.FileColumns.DATE_MODIFIED, CloudGatewayMediaStore.Files.FileColumns.DEVICE_ID,
                        CloudGatewayMediaStore.Files.FileColumns.MIME_TYPE, CloudGatewayMediaStore.Files.FileColumns.FULL_URI, FILE_ID, PARENT_ID,
                        IS_DIR_QUERY, SEARCH_NAME, PARENT_PATH};
                break;
            default:
                ret = mSearchDbTableInfo.getProjection();
                break;
        }

        return ret;
    }


    protected String getSelection(int id) {
        StringBuilder selection = new StringBuilder();
        switch (id) {
            case SEARCH_STORAGE_ID.GOOGLE_DRIVE:
            case SEARCH_STORAGE_ID.SAMSUNG_DRIVE:
                selection.append(CloudGatewayMediaStore.Files.FileColumns.DEVICE_ID).append('=').append(id);
                break;
            default:
                selection.append(mSearchDbTableInfo.getColumnName(COLUMN_ID.PATH)).append(" LIKE '")
                        .append(getStoragePath(id)).append("/%'");
                selection.append(" AND (").append(mSearchDbTableInfo.getColumnName(COLUMN_ID.FORMAT)).append(" != ")
                        .append(MtpConstants.FORMAT_ABSTRACT_AV_PLAYLIST).append(')');
                break;
        }

        if (mCurRecord != null) {
            if (!TextUtils.isEmpty(mCurRecord.getPath())) {
                selection.append(" AND ");
                if (!TextUtils.isEmpty(mCurRecord.getName())) { // Search with FolderName & FileName
                    selection.append(mSearchDbTableInfo.getColumnName(COLUMN_ID.PARENT)).append(" LIKE '")
                            .append("%/").append(mCurRecord.getPath()).append("/'");
                    addSelectionQuery(selection);
                } else { // Search with only FolderName
                    selection.append(mSearchDbTableInfo.getColumnName(COLUMN_ID.NAME)).append(" LIKE ").append(DatabaseUtils.sqlEscapeString(mCurRecord.getPath()))
                            .append(" AND ").append(mSearchDbTableInfo.getColumnName(COLUMN_ID.IS_DIRECTORY)).append(" = 1");
                }
            } else {
                if (!TextUtils.isEmpty(mCurRecord.getName())) { // Search with only FileName
                    addSelectionQuery(selection);
                }
            }

            if (!mShowHidden) {
                selection.append(" AND (").append(mSearchDbTableInfo.getColumnName(COLUMN_ID.PATH)).append(" NOT LIKE '%/.%')");
            }
        }

        return selection.toString();
    }

    protected void addSelectionQuery(StringBuilder selection) {
        if (mCurRecord != null && !TextUtils.isEmpty(mCurRecord.getName())) {
            int numberOfParams = mCurRecord.getName().split("\\s+").length;

            for (int param = 0; param < numberOfParams; param++) {
                if (selection.length() > 0) {
                    selection.append(" AND ");
                }
                selection.append(mSearchDbTableInfo.getColumnName(COLUMN_ID.NAME)).append(" LIKE ? ESCAPE '\\'");
            }
        }
    }

    private String[] getSelectionArgs() {
        String[] selectionArgs = new String[0];
        if (mCurRecord != null && !TextUtils.isEmpty(mCurRecord.getName())) {
            String[] selectionArray = mCurRecord.getName().split("\\s+");
            ArrayList<String> selectionList = new ArrayList<>();
            for (String selection : selectionArray) {
                selectionList.add("%" + selection + "%");
            }
            selectionArgs = selectionList.toArray(new String[0]);
        }

        return selectionArgs;
    }

    protected String getOrderBy(int id) {
        StringBuilder ret = new StringBuilder();

        switch (id) {
            case SEARCH_STORAGE_ID.GOOGLE_DRIVE:
            case SEARCH_STORAGE_ID.SAMSUNG_DRIVE:
                ret.append(IS_DIR).append(" DESC, ");
                ret.append(CloudGatewayMediaStore.Files.FileColumns.DATE_MODIFIED).append(" DESC, ");
                ret.append(CloudGatewayMediaStore.Files.FileColumns.DISPLAY_NAME).append(" COLLATE LOCALIZED ASC");
                break;
            default:
                // 1. Current folder
                ret.append("CASE WHEN ").append(mSearchDbTableInfo.getColumnName(COLUMN_ID.PARENT))
                        .append(" LIKE '").append(getSqlEscapeString(mPreRecord.getFullPath()))
                        .append("/' THEN 1 ELSE 0 END").append(" DESC, ");

                // 2. Child folders of the current
                ret.append("CASE WHEN ").append(mSearchDbTableInfo.getColumnName(COLUMN_ID.PATH))
                        .append(" LIKE '").append(getSqlEscapeString(mPreRecord.getFullPath()))
                        .append("%' THEN 1 ELSE 0 END").append(" DESC, ");

                // 3. Matched by keyword
                ret.append("CASE WHEN ").append(mSearchDbTableInfo.getColumnName(COLUMN_ID.NAME))
                        .append(" LIKE '").append(getSqlEscapeString(mCurRecord.getName()))
                        .append("%' THEN 1 ELSE 0 END").append(" DESC, ");

                // 4. Directory to file
                ret.append(mSearchDbTableInfo.getColumnName(COLUMN_ID.IS_DIRECTORY)).append(" DESC");

                break;
        }

        return ret.toString();
    }

    private String getSqlEscapeString(String str) {
        if (str != null) {
            return str.contains("'") ? str.replaceAll("'", "''") : str;
        }
        return null;
    }

    private String getStoragePath(int storageId) {
        String path = null;
        switch (storageId) {
            case SEARCH_STORAGE_ID.INTERNAL:
                path = AppConstants.StoragePath.INTERNAL_ROOT;
                break;
            case SEARCH_STORAGE_ID.SDCARD:
                if (StorageMonitor.isSdCardMounted()) {
                    path = StorageMonitor.getExtSDCardPath();
                }
                break;
            case SEARCH_STORAGE_ID.PRIVATE:
                if (StorageMonitor.isPrivateModeDirMounted(mContext)) {
                    path = PrivateModeMgr.getInstance(mContext).getRootDir();
                }
                break;
            default:
                break;
        }
        return path;
    }

    private boolean isDetailList(View v) {
        boolean bRet = false;

        int id = v.getId();
        if (id == R.id.file_detail_list_item) {
            bRet = true;
        }
        return bRet;
    }

    private String sizeSetter(long fileSize) {
        String formatSize = Formatter.formatFileSize(mContext, fileSize);

        if (fileSize < FileUtils.KILO_BYTES) {
            formatSize = fileSize + mContext.getResources().getString(R.string.bytes_tts);
        }

        return formatSize;
    }

    private FileRecord getRealCloudFileRecord(Cursor groupCursor, Cursor cursor) {
        CloudFileRecord ret = null;

        if (cursor != null && groupCursor != null) {
            int id = cursor.getInt(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns._ID));
            int deviceId = cursor.getInt(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.DEVICE_ID));
            String fileId = cursor.getString(cursor.getColumnIndex(FILE_ID));
            String path = cursor.getString(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.DATA));
            String name = cursor.getString(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.DISPLAY_NAME));
            String deviceName = groupCursor.getString(groupCursor.getColumnIndex(CloudGatewayMediaStore.DeviceColumns.ALIAS_NAME));
            if (!TextUtils.isEmpty(path) && !TextUtils.isEmpty(name)) {
                path = "/" + deviceName + path.substring(0, path.length() - name.length() - 1);
            } else {
                Log.e(this, "maybe path is null(empty)");
            }

            long size = cursor.getLong(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.SIZE));
            int isDirectory = cursor.getInt(cursor.getColumnIndex(IS_DIR));
            long date = cursor.getLong(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.DATE_MODIFIED)) * 1000;
            String mimeType = cursor.getString(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.MIME_TYPE));
            int fileType = MediaFile.getFileTypeForMimeType(mimeType);

            String googleDocsLink = null;

            int childItemCount = 0;

            if (isDirectory == 1) {
                fileType = FileType.FOLDER;
            } else if (mimeType != null && !mimeType.isEmpty() && FileUtils.isGoogleDocs(mimeType)) {
                googleDocsLink = cursor.getString(cursor.getColumnIndex(CloudGatewayMediaStore.Files.FileColumns.FULL_URI));
            }

            ArrayList<String> grandParentIds = new ArrayList<>();
            ArrayList<String> parentIds = new ArrayList<>();

            int deviceID = groupCursor.getInt(groupCursor.getColumnIndex(CloudGatewayMediaStore.DeviceColumns._ID));
            Uri cloudUri = CloudGatewayMediaStore.CloudFiles.getCloudFileUri(deviceID);
            try (Cursor mCursor = mContext.getContentResolver().query(cloudUri, mParentProjection,
                    null, null, null, null)) {

                String parentFileId = cursor.getString(cursor.getColumnIndex(PARENT_ID));
                parentIds.add(CloudFileRecord.CLOUD_ROOT);

                if ((mCursor != null) && (mCursor.getCount() > 0) && mCursor.moveToFirst()) {
                    int fileIdIndex = mCursor.getColumnIndex(FILE_ID);
                    int parentIdIndex = mCursor.getColumnIndex(PARENT_ID);

                    String curFileId;

                    do {
                        curFileId = mCursor.getString(fileIdIndex);

                        if (curFileId.equals(parentFileId)) {
                            grandParentIds.add(parentFileId);
                            parentFileId = mCursor.getString(parentIdIndex);
                            if (CloudFileRecord.CLOUD_ROOT.equals(parentFileId)) {
                                break;
                            }

                            mCursor.moveToFirst();
                        }
                    } while (mCursor.moveToNext());

                    for (int i = grandParentIds.size() - 1; i >= 0; i--) {
                        parentIds.add(grandParentIds.get(i));
                    }
                }
            }

            ret = new CloudFileRecord(id, deviceId, fileId, parentIds, path, name, size, date,
                    fileType, 0, childItemCount, childItemCount, googleDocsLink, mimeType);
        }

        return ret;
    }

    public void selectAll(boolean selectAll) {
        mSelectAll = selectAll;
    }

    public void reload() {
        if (mGroupCursor != null && !mGroupCursor.isClosed() && mGroupCursor.moveToFirst()) {
            do {
                int id = mGroupCursor.getInt(mGroupCursor.getColumnIndex(STORAGE_ID));
                mGroupPosition.put(id, mGroupCursor.getPosition());
                mLoaderManager.restartLoader(id, null, this);
            } while (mGroupCursor.moveToNext());
        }
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }

    public boolean isGroupLoadFinish() {
        boolean bRet = true;

        for (int i = 0; i < mGroupLoading.size(); i++) {
            if (mGroupLoading.get(i)) {
                bRet = false;
                break;
            }
        }

        return bRet;
    }

    public int getCollapsedChildrenCount(int groupPosition) {
        return mGroupChildCount == null ? 0 : mGroupChildCount.get(groupPosition);
    }

    private String getGroupTitle(String title) {
        return (SAMSUNG_DRIVE_NAME.equals(title) ? mContext.getString(UiUtils.getSamsungDriveString()) : title);
    }

    public boolean isOnlyGroupShown() {
        int num = 0;
        if (mGroupChildCount != null) {
            int count = getGroupCount();
            for (int i = 0; i < count; i++) {
                if (mGroupChildCount.get(i) != 0) {
                    num++;
                }
            }
        }
        return num == 1;
    }
}